#include "parser.h"
#include "common.h"
#include "utils.h"
#include "obj_string.h"
#include "class.h"

struct KeywordToken
{
    char *keyword;
    uint8_t length;
    TokenType token;
};  // 关键字(保留字)结构

struct KeywordToken keywordToken[] = 
{
    {"var",      3, TOKEN_VAR},
    {"fun",      3, TOKEN_FUN},
    {"if",       2, TOKEN_IF},
    {"else",     4, TOKEN_ELSE},
    {"true",     4, TOKEN_TRUE},
    {"false",    5, TOKEN_FALSE},
    {"while",    5, TOKEN_WHILE},
    {"for",      3, TOKEN_FOR},
    {"break",    5, TOKEN_BREAK},
    {"continue", 8, TOKEN_CONTINUE},
    {"return",   6, TOKEN_RETURN},
    {"null",     4, TOKEN_NULL},
    {"class",    5, TOKEN_CLASS},
    {"is",       2, TOKEN_IS},
    {"static",   6, TOKEN_STATIC},
    {"this",     4, TOKEN_THIS},
    {"super",    5, TOKEN_SUPER},
    {"import",   6, TOKEN_IMPORT},
    {NULL,       0, TOKEN_UNKNOWN}
};

/**
 * @brief 判断start是否为关键字并返回相应的token
*/
static TokenType id_ok_keyword(const char *start, uint32_t length)
{
    uint32_t idx = 0;
    while (keywordToken[idx].keyword != NULL)
    {
        if (keywordToken[idx].length == length && \
            memcmp(keywordToken[idx].keyword, start, length) == 0)
        {
            return keywordToken[idx].token;
        }
        idx ++;
    }
    return TOKEN_ID;
}

/**
 * @brief 查看下一个字符
*/
char look_ahead_char(Parser *parser)
{   
    return *parser->next_char_ptr;
}

/**
 * @brief 获取下一个字符
*/
static void get_next_char(Parser *parser)
{
    parser->cur_char = *parser->next_char_ptr ++;
}

/**
 * @brief 查看下一个字符是否为期望的，如果是就读进来，否则返回false
*/
static bool match_next_char(Parser *parser, char expected_char)
{
    if (look_ahead_char(parser) == expected_char)
    {
        get_next_char(parser);
        return true;
    }
    return false;
}

/**
 * @brief 跳过连续的空白字符
*/
static void skip_blanks(Parser *parser)
{
    while (isspace(parser->cur_char))
    {
        if (parser->cur_char == '\n')
        {
            parser->cur_token.lineNo ++;
        }
        get_next_char(parser);
    }
}

/**
 * @brief 解析标识符
*/
static void parse_id(Parser *parser, TokenType type)
{
    while (isalnum(parser->cur_char) || parser->cur_char == '_')
    {
        get_next_char(parser);
    }
    // next_char_ptr会指向第一个不合法字符的下一个字符，因此-1
    uint32_t length = (uint32_t)(parser->next_char_ptr - parser->cur_token.start - 1);
    if (type != TOKEN_UNKNOWN)
    {
        parser->cur_token.type = type;
    }
    else
    {
        parser->cur_token.type = id_ok_keyword(parser->cur_token.start, length);
    }
    parser->cur_token.length = length;
}

/**
 * @brief 解析Unicode码点
*/
static void parse_unicode_code_point(Parser *parser, ByteBuffer *buf)
{
    uint32_t idx = 0;
    int value = 0;
    uint8_t digit = 0;

    // 获取数值，u后面跟着4位十六进制数字
    while (idx ++ < 4)
    {
        get_next_char(parser);
        if (parser->cur_char == '\0')
        {
            LEX_ERROR(parser, "unterminated unicode!");
        }
        if (parser->cur_char >= '0' && parser->cur_char <= '9')
        {
            digit = parser->cur_char - '0';
        }
        else if (parser->cur_char >= 'a' && parser->cur_char <= 'f')
        {
            digit = parser->cur_char - 'a' + 10;
        }
        else if (parser->cur_char >= 'A' && parser->cur_char <= 'F')
        {
            digit = parser->cur_char - 'A' + 10;
        }
        else
        {
            LEX_ERROR(parser, "invalid unicode!");
        }
        value = value * 16 | digit;
    }

    uint32_t byte_num = get_byte_num_of_encode_utf8(value);
    ASSERT(byte_num != 0, "utf8 encode bytes should be between 1 and 4!");

    // TODO 直接写buf->datas，再次先写入byte_num个0，以保证实现有byte_num个空间
    Byte_buffer_fill_write(parser->vm, buf, 0, byte_num);

    // 把value编码为UTF-8后写入缓冲区buf
    encode_utf8(buf->datas + buf->count - byte_num, value);
}

/**
 * @brief 解析字符串
*/
static void parse_string(Parser *parser)
{
    ByteBuffer str;
    Byte_buffer_init(&str);
    while (true)
    {
        get_next_char(parser);

        if (parser->cur_char == '\0')  // \0是字符串结束标识，应该在"之后
        {
            LEX_ERROR(parser, "unterminated string!");
        }
        if (parser->cur_char == '"')
        {
            parser->cur_token.type = TOKEN_STRING;
            break;
        }
        if (parser->cur_char == '%')  // 内嵌表达式%()
        {
            if (!match_next_char(parser, '('))
            {
                LEX_ERROR(parser, "\'%\' should followed by \'(\'!");
            }
            if (parser->interpolation_expect_right_parent_num > 0)  // 只支持一层内嵌表达式
            {
                COMPILE_ERROR(parser, "sorry, I don't support nest interpolate expression!");
            }
            parser->interpolation_expect_right_parent_num = 1;
            parser->cur_token.type = TOKEN_INTERPOLATION;
            break;
        }
        if (parser->cur_char == '\\')
        {
            get_next_char(parser);
            switch (parser->cur_char)
            {
                case '0':
                    Byte_buffer_add(parser->vm, &str, '\0');
                    break;
                case 'a':
                    Byte_buffer_add(parser->vm, &str, '\a');
                    break;
                case 'b':
                    Byte_buffer_add(parser->vm, &str, '\b');
                    break;
                case 'f':
                    Byte_buffer_add(parser->vm, &str, '\f');
                    break;
                case 'n':
                    Byte_buffer_add(parser->vm, &str, '\n');
                    break;
                case 'r':
                    Byte_buffer_add(parser->vm, &str, '\r');
                    break;
                case 't':
                    Byte_buffer_add(parser->vm, &str, '\t');
                    break;
                case 'u':
                    parse_unicode_code_point(parser, &str);
                    break;
                case '"':
                    Byte_buffer_add(parser->vm, &str, '"');
                    break;
                case '\\':
                    Byte_buffer_add(parser->vm, &str, '\\');
                    break;  
                default:
                    LEX_ERROR(parser, "unsupport escape \\%c", parser->cur_char);
                    break;                                 
            }
        }            
        else
        {
            Byte_buffer_add(parser->vm, &str, parser->cur_char);
        }
    }
    // 用识别到的字符串新建字符串对象存储到cur_token的value中
    ObjString *obj_string = new_objString(parser->vm, (const char *)str.datas, str.count);
    parser->cur_token.value = OBJ_TO_VALUE(obj_string);
    Byte_buffer_clear(parser->vm, &str);
}

/**
 * @brief 跳过一行
*/
static void skip_a_line(Parser *parser)
{
    get_next_char(parser);
    while (parser->cur_char != '\0')
    {
        if (parser->cur_char == '\n')
        {
            parser->cur_token.lineNo ++;
            get_next_char(parser);
            break;
        }
        get_next_char(parser);
    }
}

/**
 * @brief 跳过行注释或区块注释
*/
static void skip_comment(Parser *parser)
{
    char next_char = look_ahead_char(parser);
    if (parser->cur_char == '/')
    {
        skip_a_line(parser);
    }
    else
    {
        while (next_char != '*' && next_char != '\0')
        {
            get_next_char(parser);
            if (parser->cur_char == '\n')
            {
                parser->cur_token.lineNo ++;
            }
            next_char = look_ahead_char(parser);
        }
        if (match_next_char(parser, '*'))
        {
            if (!match_next_char(parser, '/'))
            {
                LEX_ERROR(parser, "expect '/' after '*'!");
            }
            get_next_char(parser);
        }
        else
        {
            LEX_ERROR(parser, "expect '*/' before file end!");
        }
    }
    skip_blanks(parser); // 注释之后有可能会有空白字符
}

/**
 * @brief 获取下一个token
*/
void get_next_token(Parser *parser)
{
    // 这里的pre_token实际上是下一个token
    // 此处主要起到备份作用
    parser->pre_token = parser->cur_token;
    skip_blanks(parser);
    parser->cur_token.type = TOKEN_EOF;  // 默认文件结束
    parser->cur_token.length = 0;
    /**
     * next_char_ptr始终指向cur_char的后面的字符
     * 对于识别单词来说，next_char_ptr指向的是上次调用get_next_token识别单词时遇到的不符合规则字符的下一个字符的地址
    */
    parser->cur_token.start = parser->next_char_ptr - 1;
    parser->cur_token.value = VT_TO_VALUE(VT_UNDEFINED); // 默认是VT_UNDEFINED
    while (parser->cur_char != '\0')
    {
        switch (parser->cur_char)
        {
            case ',':
                parser->cur_token.type = TOKEN_COMMA;
                break;
            case ':':
                parser->cur_token.type = TOKEN_COLON;
                break;
            case '(':
                if (parser->interpolation_expect_right_parent_num > 0)
                {
                    parser->interpolation_expect_right_parent_num ++;
                }
                parser->cur_token.type = TOKEN_LEFT_PAREN;
                break;
            case ')':
                if (parser->interpolation_expect_right_parent_num > 0)
                {
                    parser->interpolation_expect_right_parent_num --;
                    if (parser->interpolation_expect_right_parent_num == 0)
                    {
                        parse_string(parser);
                        break;
                    }
                }
                parser->cur_token.type = TOKEN_RIGHT_PAREN;
                break;
            case '[':
                parser->cur_token.type = TOKEN_LEFT_BRACKET;
                break;
            case ']':
                parser->cur_token.type = TOKEN_RIGHT_BRACKET;
                break;
            case '{':
                parser->cur_token.type = TOKEN_LEFT_BRACE;
                break;
            case '}':
                parser->cur_token.type = TOKEN_RIGHT_BRACE;
                break;
            case '.':
                if (match_next_char(parser, '.'))
                {
                    parser->cur_token.type = TOKEN_DOT_DOT;
                }
                else
                {
                    parser->cur_token.type = TOKEN_DOT;
                }
                break;
            case '=':
                if (match_next_char(parser, '='))
                {
                    parser->cur_token.type = TOKEN_EQUAL;
                }
                else
                {
                    parser->cur_token.type = TOKEN_ASSIGN;
                }
                break;
            case '+':
                parser->cur_token.type = TOKEN_ADD;
                break;
            case '-':
                parser->cur_token.type = TOKEN_SUB;
            case '*':
                parser->cur_token.type = TOKEN_MUL;
                break;
            case '/':
                if (match_next_char(parser, '/') || match_next_char(parser, '*'))
                {
                    skip_comment(parser);

                    // 重置下一个token起始地址
                    parser->cur_token.start = parser->next_char_ptr - 1;
                    continue;
                }
                else
                {
                    parser->cur_token.type = TOKEN_DIV;
                }
                break;
            case '%':
                parser->cur_token.type = TOKEN_MOD;
                break;
            case '&':
                if (match_next_char(parser, '&'))
                {
                    parser->cur_token.type = TOKEN_LOGIC_AND;
                }
                else
                {
                    parser->cur_token.type = TOKEN_BIT_AND;
                }
                break;
            case '|':
                if (match_next_char(parser, '|'))
                {
                    parser->cur_token.type = TOKEN_LOGIC_OR;
                }
                else
                {
                    parser->cur_token.type = TOKEN_BIT_OR;
                }
                break;
            case '~':
                parser->cur_token.type = TOKEN_BIT_NOT;
                break;
            case '?':
                parser->cur_token.type = TOKEN_QUESTION;
                break;
            case '>':
                if (match_next_char(parser, '='))
                {
                    parser->cur_token.type = TOKEN_GREATE_EQUAL;
                }
                else if (match_next_char(parser, '>'))
                {
                    parser->cur_token.type = TOKEN_BIT_SHIFT_RIGHT;
                }
                else
                {
                    parser->cur_token.type = TOKEN_GREATE;
                }
                break;
            case '<':
                if (match_next_char(parser, '='))
                {
                    parser->cur_token.type = TOKEN_LESS_EQUAL;
                }
                else if (match_next_char(parser, '<'))
                {
                    parser->cur_token.type = TOKEN_BIT_SHIFT_LEFT;
                }
                else
                {
                    parser->cur_token.type = TOKEN_LESS;
                }
                break;
            case '!':
                if (match_next_char(parser, '='))
                {
                    parser->cur_token.type = TOKEN_NOT_EQUAL;
                }
                else
                {
                    parser->cur_token.type = TOKEN_LOGIC_NOT;
                }
                break;
            case '"':
                parse_string(parser);
                break;
            default:
                // 处理变量名或者数字
                // 变量名首字符是字母或下划线_
                if (isalpha(parser->cur_char) || parser->cur_char == '_')
                {
                    // 去解析变量名其余的部分
                    parse_id(parser, TOKEN_UNKNOWN);
                }
                else if (isdigit(parser->cur_char)) // 数字
                {
                    parser_num(parser);
                }
                else  
                {
                    if (parser->cur_char = '#' && match_next_char(parser, '!'))  // 魔数#!
                    {
                        skip_a_line(parser);
                        parser->cur_token.start = parser->next_char_ptr - 1;
                        // 重置下一个token起始地址
                        continue;
                    }
                    LEX_ERROR(parser, "unsupport char: \'%c\', quit", parser->cur_char);
                }
                return;
        }
        // 大部分case出口
        parser->cur_token.length = (uint32_t)(parser->next_char_ptr - parser->cur_token.start);
        get_next_char(parser);
        return;
    }
}

/**
 * @brief 若当前token位恶心赔偿特的则读入下一个token，并返回true
 * 否则不读入token且返回false
*/
bool match_token(Parser *parser, TokenType expected)
{
    if (parser->cur_token.type == expected)
    {
        get_next_token(parser);
        return true;
    }
    return false;
}

/**
 * @brief 断言当前token为expected并读入下一个token，否则报错error
*/
void consume_cur_token(Parser *parser, TokenType expected, const char *err_msg)
{
    if (parser->cur_token.type != expected)
    {
        COMPILE_ERROR(parser, err_msg);
    }
    get_next_token(parser);
}

/**
 * @brief 断言下一个token为expected，否则报错err_msg
*/
void consum_next_token(Parser *parser, TokenType expected, const char * err_msg)
{
    get_next_token(parser);
    if (parser->cur_token.type != expected)
    {
        COMPILE_ERROR(parser, err_msg);
    }
}

/**
 * @brief 由于source_code未必来自于文件file，有可能只是一个字符串
 * @param file 仅用作跟踪待编译的代码的标识，方便报错 
*/
void init_parser(VM *vm, Parser *parser, const char *file, const char *source_code, ObjModule *obj_module)
{
    parser->file = file;
    parser->source_code = source_code;
    // 当前字符cur_chart等于源码串的首字符
    parser->cur_char = *parser->source_code;
    // 使下一个字符的地址next_char_ptr等于源码串首字符的下一个字符
    // 这样在获取下一字符时可以直接从源码串中获取，每次读取一个字符后再使
    // next_char_ptr自动加1就完成了更新，而无需调用get_char之类的函数
    parser->next_char_ptr = parser->source_code + 1;
    // 行号
    parser->cur_token.lineNo = 1;
    // 默认设置 TOKEN_UNKNOWN
    parser->cur_token.type = TOKEN_UNKNOWN;
    parser->cur_token.start = NULL;
    parser->cur_token.length = 0;
    parser->pre_token = parser->cur_token;
    parser->interpolation_expect_right_parent_num = 0;
    parser->vm = vm;
    parser->cur_module = obj_module;
}

/**
 * @brief 解析十六进制数字
*/
static void parse_hex_num(Parser *parser)
{
    while (isxdigit(parser->cur_char))
    {
        get_next_char(parser);
    }
}

/**
 * @brief 解析十进制数字
*/
static void parse_dec_num(Parser *parser)
{
    while (isdigit(parser->cur_char))
    {
        get_next_char(parser);
    }

    if (parser->cur_char == '.' && isdigit(look_ahead_char(parser)))
    {
        get_next_char(parser);
        while (isdigit(parser->cur_char))
        {
            get_next_char(parser);
        }
    }
}

/**
 * @brief 解析八进制
*/
static void parse_oct_num(Parser *parser)
{
    while (parser->cur_char >= '0' && parser->cur_char < '8')
    {
        get_next_char(parser);
    }
}

/**
 * @brief 解析八进制 十进制 十六进制，仅支持前缀形式，后缀形式不支持
*/
static void parser_num(Parser *parser)
{
    if (parser->cur_char == '0' && match_next_char(parser, 'x'))
    {
        get_next_char(parser);
        parse_hex_num(parser);
        parser->cur_token.value = NUM_TO_VALUE(strtol(parser->cur_token.start, NULL, 16));
    }
    else if (parser->cur_char == '0' && isdigit(look_ahead_char(parser)))
    {
        parse_oct_num(parser);
        parser->cur_token.value = NUM_TO_VALUE(strtol(parser->cur_token.start, NULL, 8));
    }
    else
    {
        parse_dec_num(parser);
        parser->cur_token.value = NUM_TO_VALUE(strtod(parser->cur_token.start, NULL));
    }
    // next_char_ptr会指向第一个不合法字符的下一个字符，因此-1
    parser->cur_token.length = (uint32_t)(parser->next_char_ptr - parser->cur_token.start - 1);
    parser->cur_token.type = TOKEN_NUM;
}